package com.naiterui.ehp.bs.doctor.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.consult.CommentBO;
import com.naiterui.ehp.bp.bo.consult.CommentDetailBO;
import com.naiterui.ehp.bp.bo.consult.VideoConsultBO;
import com.naiterui.ehp.bp.bo.patient.PatientInquirerBO;
import com.naiterui.ehp.bp.constants.CommonConstant.ConsultType;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DrConsultComment;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.fegin.PatientFeignClient;
import com.naiterui.ehp.bs.doctor.fegin.RecomFeginClient;
import com.naiterui.ehp.bs.doctor.fegin.VideoConsultFeignClient;
import com.naiterui.ehp.bs.doctor.repository.IDoctorRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrConsultCommentRepository;
import com.naiterui.ehp.bs.doctor.service.IConsultCommentService;
import com.naiterui.ehp.bs.doctor.service.IConsultSessionService;
import com.naiterui.ehp.bs.doctor.service.IPatientService;
import com.naiterui.ehp.bs.doctor.utils.PropertyValueConstants;
import com.naiterui.ehp.bs.doctor.vo.patient.ConsultCommentVO;

import lombok.extern.slf4j.Slf4j;

/**
 * @Description 会话评价
 * @Author gongbaoqiang
 * @Date 2020/7/1 10:09 AM
 */
@Slf4j
@Service
public class AdConsultCommentServiceImpl implements IConsultCommentService {
    @Autowired
    private IDrConsultCommentRepository consultCommentRepository;

    @Autowired
    private IPatientService patientService;

    @Autowired
    private IConsultSessionService consultSessionService;

    @Autowired
    private RecomFeginClient recomFeginClient;

    @Autowired
    private PatientFeignClient patientFeignClient;

    @Autowired
    private VideoConsultFeignClient videoConsultFeignClient;

    @Autowired
    private IDoctorRepository doctorRepository;

    /**
     * 星级最高分数
     */
    public static final int STARS_LEVEL_SCORE = 5;

    @Override
    public PageVO<CommentDetailBO> findByDoctorId(Long doctorId, PageParamVO pageParamVO) throws BusinessException {
        Page<DrConsultComment> page = consultCommentRepository.findByDoctorIdOrderByIdDesc(doctorId, pageParamVO.getPageable());
        List<DrConsultComment> commentList = page.getContent();
        List<ConsultCommentVO> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(commentList)) {
            Set<Long> patientIds = new HashSet<>();
            Set<Long> consultSessionIds = new HashSet<>();
            Set<Long> videoConsultSessionIds = new HashSet<>();
            commentList.forEach(s -> {
                patientIds.add(s.getPatientId());
                if (ConsultType.GRAPHIC == s.getConsultType()) {
                    consultSessionIds.add(s.getConsultSessionId());
                }
                if (ConsultType.VIDEO == s.getConsultType()) {
                    videoConsultSessionIds.add(s.getConsultSessionId());
                }
            });
            //患者头像
            Map<Long, Patient> patientMap = patientService.getPatientMap(patientIds);

            //就诊人信息
            Map<Long, Long> sessionMap = consultSessionService.findInquirerByIds(consultSessionIds);
            Map<Long, Long> videoConsultMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(videoConsultSessionIds)) {
                List<VideoConsultBO> videoConsultBOS = videoConsultFeignClient.getVideoConsult(videoConsultSessionIds);
                videoConsultMap = videoConsultBOS.stream().collect(Collectors.toMap(VideoConsultBO::getId, VideoConsultBO::getInquirerId, (a, b) -> b));
            }
            List<Long> inquirerIds = new ArrayList<>(sessionMap.values());
            inquirerIds.addAll(videoConsultMap.values());
            List<PatientInquirerBO> inquirers = patientFeignClient.patientInquirerList(inquirerIds);
            Map<Long, PatientInquirerBO> inquirerMap = inquirers.stream().collect(Collectors.toMap(PatientInquirerBO::getInquirerId, Function.identity()));

            Map<Long, Long> finalVideoConsultMap = videoConsultMap;
            result = commentList.stream().map(s -> {
                        PatientInquirerBO inquirerBO = ConsultType.GRAPHIC == s.getConsultType() ?
                                inquirerMap.get(sessionMap.get(s.getConsultSessionId())) : inquirerMap.get(finalVideoConsultMap.get(s.getConsultSessionId()));
                        return getCommentVO(s, patientMap.get(s.getPatientId()), inquirerBO);
                    }
            ).collect(Collectors.toList());
        }

        return PageVO.newBuilder()
                .pageNo(page.getNumber())
                .pageSize(page.getSize())
                .totalCount((int) page.getTotalElements())
                .result(result)
                .build();
    }

    @Override
    public ConsultCommentVO getDetail(Long commentId) throws BusinessException {
        DrConsultComment comment = findById(commentId);
        Map<Long, Patient> patientMap = patientService.getPatientMap(Sets.newHashSet(comment.getPatientId()));

        Long inquirerId = getInquirerId(comment.getConsultType(), comment.getConsultSessionId());
        List<PatientInquirerBO> inquirers = patientFeignClient.patientInquirerList(Lists.newArrayList(inquirerId));

        return getCommentVO(comment, patientMap.get(comment.getPatientId()), inquirers.get(0));
    }

    @Override
    public Long submit(CommentBO commentBO) throws BusinessException {
        if (existByConsultSession(commentBO.getSessionId(), commentBO.getType())) {
            throw new BusinessException(ExceptionCodes.CONSULT_COMMENT_IS_EXIST);
        }
        DrConsultComment comment = new DrConsultComment();
        comment.setDoctorId(commentBO.getDoctorId());
        comment.setPatientId(commentBO.getPatientId());
        comment.setStarLevel(commentBO.getStarsLevel());
        comment.setConsultType(commentBO.getType());
        comment.setConsultSessionId(commentBO.getSessionId());
        String commentContent = commentBO.getStarsContent();
        if (StringUtils.isNotBlank(commentContent)) {
            if (StringUtils.isNotBlank(commentBO.getContent())) {
                commentContent = StringUtils.join(commentContent, ",", commentBO.getContent());
            }
        } else {
            commentContent = commentBO.getContent();
        }
        comment.setCommentContent(commentContent);
        //从会话中获取就诊人
        Long inquirerId = getInquirerId(comment.getConsultType(), comment.getConsultSessionId());
        //保存患者最新诊断
        List<String> diagnosis = recomFeginClient.getDiagnosis(comment.getDoctorId(), inquirerId);
        log.info("医生对患者和的最新诊断：diagnosis={}", diagnosis.toString());
        comment.setDiagnosis(diagnosis.stream().collect(Collectors.joining(",")));
        comment.setCreatedAt(new Date());
        comment.setWac(commentBO.getWac());
        consultCommentRepository.save(comment);

        //递增缓存好评总分和评价总分
        RedisUtil.keyOps().incrBy(PropertyValueConstants.RDS_CONSULT_COMMENT_APPLAUSE_SCORE + comment.getDoctorId(), comment.getStarLevel());
        RedisUtil.keyOps().incrBy(PropertyValueConstants.RDS_CONSULT_COMMENT_TOTAL_SCORE + comment.getDoctorId(), STARS_LEVEL_SCORE);
        return comment.getId();

    }

    @Override
    public void replay(Long commentId, String content) throws BusinessException {
        DrConsultComment comment = findById(commentId);
        comment.setReply(content);
        comment.setChangedAt(new Date());
        consultCommentRepository.update(comment);

        //推送医生回复
        Doctor doctor = doctorRepository.get(comment.getDoctorId());
        String msg = String.format(ConfigUtil.getString("consult.comment.reply.msg"), doctor.getName());
        // patientFeignClient.consultCommentReply(comment.getPatientId(), StringUtils.join(msg, "\n", content));
    }

    @Override
    public Map<Long, String> getApplauseRate(List<Long> doctorIds) {
        Map<Long, String> map = new HashMap<>();
        doctorIds.forEach(s -> {
            map.put(s, getApplauseRate(s));
        });
        return map;
    }

    @Override
    public Boolean existByConsultSession(Long consultSessionId, Integer consultType) throws BusinessException {
        return consultCommentRepository.findFirstByConsultSessionIdAndConsultType(consultSessionId, consultType) == null ? false : true;
    }

    @Override
    public CommentDetailBO getConsultSessionCommont(Long consultSessionId, Integer consultType) {
        DrConsultComment consultComment =
            consultCommentRepository.findFirstByConsultSessionIdAndConsultType(consultSessionId, consultType);
        if (consultComment == null) {
            return null;
        }
        CommentDetailBO commentDetailBO = new CommentDetailBO();
        BeanUtil.copyProperties(consultComment, commentDetailBO);
        return commentDetailBO;
    }

    /**
     * 获取医生好评率
     *
     * @return
     */
    private String getApplauseRate(Long doctorId) {
        Object applauseScore = RedisUtil.valueOps().getObject(PropertyValueConstants.RDS_CONSULT_COMMENT_APPLAUSE_SCORE + doctorId);
        Object totalScore = RedisUtil.valueOps().getObject(PropertyValueConstants.RDS_CONSULT_COMMENT_TOTAL_SCORE + doctorId);
        if (applauseScore == null) {
            return "100%";
        }
        BigDecimal applause = new BigDecimal(applauseScore.toString());
        BigDecimal total = new BigDecimal(totalScore.toString());
        String rate = applause.multiply(new BigDecimal(100)).divide(total, 1, RoundingMode.FLOOR).toString();

        return rate + "%";
    }


    private Long getInquirerId(Integer consultType, Long consultId) throws BusinessException {
        Long inquirerId = -1L;
        if (ConsultType.GRAPHIC == consultType) {
            inquirerId = consultSessionService.findInquirerById(consultId);
        }
        if (ConsultType.VIDEO == consultType) {
            inquirerId = videoConsultFeignClient.getVideoConsultById(consultId).getInquirerId();
        }
        return inquirerId;
    }

    private DrConsultComment findById(Long id) throws BusinessException {
        DrConsultComment comment = consultCommentRepository.get(id);
        if (comment == null) {
            throw new BusinessException(ExceptionCodes.CONSULT_COMMENT_NOT_EXIST);
        }
        return comment;
    }


    private ConsultCommentVO getCommentVO(DrConsultComment comment, Patient patient, PatientInquirerBO inquirer) {
        String patientNickName = inquirer.getName();
        if (StringUtils.isNotBlank(patientNickName) && DrConsultComment.WAC_ANONYMITY == comment.getWac()) {
            //匿名评论转换姓后面的为*号
            patientNickName = StringUtil.replaceNameX(patientNickName);
        }
        return ConsultCommentVO.builder()
                .commentId(comment.getId())
                .starLevel(comment.getStarLevel())
                .commentContent(StringUtils.isNotBlank(comment.getCommentContent()) ? comment.getCommentContent() : "")
                .createdAt(comment.getCreatedAt())
                .diagnosis(comment.getDiagnosis())
                .reply(comment.getReply())
                .patientNickName(patientNickName)
                .patientHeadUrl(patient.getHeadUrl())
                .wac(comment.getWac())
                .build();
    }
}
